package worker

import (
	"crontab/common"
	"errors"
	"fmt"
	"github.com/samuel/go-zookeeper/zk"
	"time"
)

//部署到/cron/works
type ServerRegister struct {
	conn    *zk.Conn
	localIP string //本地IP
}

var (
	G_ServerRegister *ServerRegister
)

func InitServerRegister() (err error) {
	var (
		localIP string
	)
	con, connChan, err := zk.Connect(G_Config.ZKEndPoint, time.Duration(G_Config.ZKConnectTimeout)*time.Millisecond)
	if err != nil {

		return err
	}

	for {
		isConnect := false
		select {
		case connEvent := <-connChan:
			if connEvent.State == zk.StateConnected {
				isConnect = true
				fmt.Println("connect to zookeeper server success")
			}
		case _ = <-time.After(time.Duration(G_Config.ZKConnectTimeout) * time.Millisecond):
			return errors.New("connect to zookeeper server timeout")

		}
		if isConnect {

			break
		}
	}
	if localIP, err = common.GetLocalIP(); err != nil {
		con.Close()
		return
	}
	G_ServerRegister = &ServerRegister{
		conn:    con,
		localIP: localIP,
	}
	//计算本地IP

	//创建根节点,"/cron/jobs"
	if _, err := G_ServerRegister.CreatePath(common.JOB, []byte(""), 0); err == nil {
		if _, err := G_ServerRegister.CreatePath(common.JOB_WORKS_PATH, []byte(""), 0); err == nil {
			G_ServerRegister.KeepOnline()
			return nil
		}
	}

	G_ServerRegister.conn.Close()

	return err
}

func (register *ServerRegister) CreatePath(path string, data []byte, flag int32) (str string, err error) {

	var (
		exists bool
	)
	exists, _, err = register.conn.Exists(path)
	if err != nil {
		return "", err
	}
	if !exists {
		str, err = register.conn.Create(path, data, flag, zk.WorldACL(zk.PermAll))
		if err != nil && err != zk.ErrNodeExists {
			return "", err
		}

	}
	return path, err
}

func (register *ServerRegister) SetData(path string, data []byte, flag int32) (err error) {
	if _, err = register.CreatePath(path, data, flag); err == zk.ErrNodeExists || err == nil {

		register.conn.Set(path, data, -1)
		return nil
	}

	return err
}

//注册到zookeeper中，注册为临时节点
func (register *ServerRegister) KeepOnline() {
	var (
		regPath  string
		err      error
		retryCnt int
	)
	retryCnt = 0
Process:
	regPath = common.JOB_WORKS_PATH + "/" + register.localIP
	if err = register.SetData(regPath, []byte(""), 1); err != nil {
		if retryCnt > 3 {
			return
		}
		goto Retry
	}
	return
Retry:
	retryCnt++
	time.Sleep(1 * time.Second)
	goto Process
}
